# {
#     "authExtKey": "450704994719041987",
#     "empExtKey": "cs998",
#     "empType": 11,
#     "pointExtKey": "2001-0000000644",
#     "dataSysCode": 2001,
#     "authType": 1,
#     "authState": 1,
#     "beginTime": "2023-04-10 14:16:18",
#     "endTime": "2099-12-31 23:59:59",
#     "isDeleted": false,
#     "deleteTime": null,
#     "modifyTime": "2023-04-10 14:16:18",
#     "sysModifyTime": "2023-04-10 17:55:43"
# }
from module.huada.entity.base_entity import BaseEntity
from plugin import Mylogger, MSsqlClient, Config, MyTime, SchedulerManager, Trigger
from module.huada.entity.sync_entity import card_user_syn_entity

fail_reason = 1  # 1 成功 -1 人员异常 -2 凭证异常 -3 门点异常
fail_reason_dict = {"1": "成功", "-1": "人员异常，请检查人员是否同步成功", "-2": "凭证异常，请检查凭证状态", "-3": "门点异常，请检查门点是否同步成功"}


class AuthEntity(BaseEntity):
    url = "tunion/get/forbidtwo"
    table_name = "auth"
    api_data_list = []
    create_table = True
    get_time = "2000-01-01 00:00:00"
    order_by = "sysModifyTime"
    down_access_list = []  # 中间库取出的待处理数据
    cancel_access_list = []
    write_back_dict = {}
    write_back_dict_cancel = {} # 取消授权回写时会影响到授权回写，所以分开
    write_back_fail_reason = {} # 回写失败原因
    # is_start = False
    update_cache_time = "2000-01-01 00:00:00"

    def __init__(self, **kwargs) -> None:
        self.authExtKey = kwargs.get("authExtKey")  # 门禁授权主键
        self.empExtKey = kwargs.get("empExtKey")  # 员工主键
        self.empType = kwargs.get("empType")  # 员工类型
        self.pointExtKey = kwargs.get("pointExtKey")  # 门禁点主键
        self.dataSysCode = kwargs.get("dataSysCode")  # 数据系统编码
        self.authType = kwargs.get("authType")  # 授权类型 1-正向授权
        self.authState = kwargs.get("authState")  # 授权状态 1-有效 2-无效
        self.beginTime = kwargs.get("beginTime")  # 授权开始时间
        self.endTime = kwargs.get("endTime")  # 授权结束时间
        self.isDeleted = kwargs.get("isDeleted")  # 是否删除
        self.deleteTime = kwargs.get("deleteTime")  # 删除时间
        self.modifyTime = kwargs.get("modifyTime")  # 修改时间
        self.sysModifyTime = kwargs.get("sysModifyTime")  # 系统修改时间
        self.id = kwargs.get("id") or 0
        self.isdeal = kwargs.get("isdeal") or 0  # 是否处理过、以及处理次数
        self.authresult = kwargs.get("authresult") or 0  # 授权结果 1-成功 -1 人员异常 -2 凭证异常 -3 门点异常 -4 授权异常，设备可能离线
        self.reason = kwargs.get("reason") or "" # 授权结果描述

    @classmethod
    def down_access(cls, client: MSsqlClient, objs):

         # 每天更新一次人员缓存
        # if MyTime.timestamp() - int(MyTime.timestampfrom(cls.update_cache_time)) > 24 * 60 * 60:
        #     # 初始化部门缓存
        #     get_cache()
        #     cls.update_cache_time = MyTime.timestr()

        # 下发授权，objs都是取得obj.begintime 在当前+1小时内的数据 obj.authstate = 1
        global fail_reason
        finished_objs = []  # 每批次中，已经查询过的人员编号列表
        for obj in objs:
            obj.deal_result = 0
            is_exists = True
            if obj.empExtKey not in finished_objs:  # 如果没有查询过
                is_exists = check_person(obj.empExtKey)  # 获取人员缓存
            if not is_exists:
                # 没有找到人员信息
                # 记录处理次数
                # 记录失败原因 人员不存在/凭证不存在
                write_back(cls.write_back_dict, obj.id, int(obj.isdeal) - 1)  # 不再处理
                write_back(cls.write_back_fail_reason, obj.id, fail_reason)
                # Mylogger.info(f"下发授权失败，人员{obj.empExtKey} 本身/凭证/部门 可能不存在")
                continue
            finished_objs.append(obj.empExtKey) # 记录已经查询过的人员编号
            result = 1
            for info in person_cache[obj.empExtKey]:
                info_obj = card_user_syn_entity(**info)
                info_obj.validty = (info['idtype'] << 8) + (1-info['card_type'])
                info_obj.id = obj.authExtKey + '_' + info_obj.card_id_dex
                info_obj.op_date = MyTime.timestr()
                info_obj.op_type = '0001'
                info_obj.guard_group = get_addr(obj.pointExtKey)
                # info_obj.guard_group = '100-7#27-1'
                info_obj.sync_type = 1
                info_obj.synctime = ''
               
                if info_obj.guard_group is not None and info_obj.dept_name != 'None':
                    client = MSsqlClient(**Config.module_config.huada.sync_link)
                    result = client.insert_objects([info_obj], tablename=card_user_syn_entity.table_name)
                else:
                    Mylogger.info(f"授权 {obj.authExtKey} 没有对应的门禁点  {obj.pointExtKey} 或 部门 {info_obj.dept_name}")
                    fail_reason = -3  # 门点异常
                    result = 0
                if not result:
                    write_back(cls.write_back_dict, obj.id, int(obj.isdeal) - 1)
                    write_back(cls.write_back_fail_reason, obj.id, fail_reason)
                    break
            if result:
                write_back(cls.write_back_dict, obj.id, 1)
                write_back(cls.write_back_fail_reason, obj.id, fail_reason)


        return True

    @classmethod
    def cancel_access(cls, client: MSsqlClient, objs):
        # 取消授权，objs都是取得obj.endtime 小于在当前 的数据 obj.authstate = 2
         # 每天更新一次人员缓存
        # if MyTime.timestamp() - int(MyTime.timestampfrom(cls.update_cache_time)) > 24 * 60 * 60:
        #     # 初始化部门缓存
        #     get_cache()
        #     cls.update_cache_time = MyTime.timestr()
        global fail_reason
        finished_objs = []  # 每批次中，已经查询过的人员编号列表
        for obj in objs:
            obj.deal_result = 0
            is_exists = True
            if obj.empExtKey not in finished_objs:  # 如果没有查询过
                is_exists = check_person(obj.empExtKey)  # 获取人员缓存
            if not is_exists:
                write_back(cls.write_back_dict_cancel, obj.id, -99)  # 不再处理
                write_back(cls.write_back_fail_reason, obj.id, fail_reason)
                # Mylogger.info(f"删除授权失败，人员{obj.empExtKey} 本身/凭证/部门 可能不存在，不再处理")
                continue
            finished_objs.append(obj.empExtKey)
            result = 1
            for info in person_cache[obj.empExtKey]:
                info_obj = card_user_syn_entity(**info)
                info_obj.validty = (info['idtype'] << 8) + (1-info['card_type'])  # 同步库的永久和临时和数据库定义相反
                info_obj.id = obj.authExtKey
                info_obj.op_date = MyTime.timestr()
                info_obj.op_type = '0002'
                info_obj.guard_group = get_addr(obj.pointExtKey)
                info_obj.sync_type = 1
                info_obj.synctime = ''
               
                if info_obj.guard_group is not None and info_obj.dept_name != 'None':
                    client = MSsqlClient(**Config.module_config.huada.sync_link)
                    result = client.insert_objects([info_obj], tablename=card_user_syn_entity.table_name)
                else:
                    Mylogger.info(f"授权 {obj.authExtKey} 没有对应的门禁点  {obj.pointExtKey} 或 部门 {info_obj.dept_name}")
                    fail_reason = -3
                    result = 0
                if not result:
                    write_back(cls.write_back_dict_cancel, obj.id, int(obj.isdeal) - 1)
                    break
            if result:
                write_back(cls.write_back_dict_cancel, obj.id, 2)
                write_back(cls.write_back_fail_reason, obj.id, fail_reason)


        return True
    
    
    @classmethod
    def write_back_from_dict(cls, write_back_dict):
        dic = {}
        # 复制数据
        for k, v in write_back_dict.items():
            dic[k] = v.copy()
        for key, value in dic.items():
            if len(value) > 0:
                client = MSsqlClient(**Config.module_config.huada.record_link)
                # value里面每次取5000条更新
                for i in range(0, len(value), 5000):
                    end = (i + 5000) if len(value) > (i + 5000) else len(value)
                    datas = value[i:end]
                    value_str = "','".join(datas)
                    client.execute(f"update {cls.table_name} set isdeal = {key} where id in ('{value_str}')")
                    Mylogger.info(f"write back {len(datas)} records [{key}] to db {cls.table_name} success")
                    # 处理完成后，去掉处理的数据
                    write_back_dict[key] = list(set(write_back_dict[key]).difference(set(datas)))
        dic.clear()
        cls.write_back_fail_reason_method()


    @classmethod
    def write_back_fail_reason_method(cls):
        # 记录失败原因
        for k, v in cls.write_back_fail_reason.items():
            if len(v) > 0:
                client = MSsqlClient(**Config.module_config.huada.record_link)
                # value里面每次取5000条更新
                for i in range(0, len(v), 5000):
                    end = (i + 5000) if len(v) > (i+ 5000) else len(v)
                    datas = v[i:end]
                    value_str = "','".join(datas)
                    client.execute(f"update {cls.table_name} set authresult = {k},reason = {fail_reason_dict[k]} where id in ('{value_str}')")
                    # 处理完成后，去掉处理的数据
                    cls.write_back_fail_reason[k] = list(set(cls.write_back_fail_reason[k]).difference(set(datas)))
        


def write_back(dic, id, result):
    # 记录操作结果到dic中
    key = result
    if not dic.__contains__(str(key)):
        dic[str(key)] = []
    dic[str(key)].append(str(id))


def get_addr(pointcode):
    # pointcode去掉前面的systemcode+ '-'后，按每三位分割
    # 例如：2001-001001001491，去掉2001-后，按每三位分割，得到001,001,001,491
    try:
        _addr = pointcode.split('-')[1]
        if len(_addr) != 12:
            Mylogger.error(f"授权同步失败，门点编码{pointcode}格式错误")
            return None
        addr = f"{int(_addr[0:3])}-{int(_addr[3:6])}#{int(_addr[6:9])}-{int(_addr[9:12])}"
        return addr
    except Exception as e:
        Mylogger.error(f"授权同步失败，门点编码{pointcode}格式错误")
        return None


def check_person(person_code):
    """ 检查人员是否存在 """

    # 去数据库查一次
    global fail_reason
    client = MSsqlClient(charset='cp936', **Config.module_config.huada.client_link)
    results1 = client.select_to_dict(f"""
    select *
    from acscon_user
    where usercode = '{person_code}' 
    """)
    if not (results1 and len(results1) > 0):
        fail_reason = -1  # 人员不存在
        Mylogger.error(f"授权同步失败，人员{person_code} 本身不存在")
        return False

    results = client.select_to_dict(f"""
    select a.usercode as empo
        ,a.name     as name_cn
        ,a.sex      as sex
        ,c.cardno   as card_id_dex
        ,c.idtype   as idtype
        ,c.startdate as validty_begintime
        ,c.enddate  as validty_endtime
        ,f.type     as card_type
        ,e.name     as dept_name
    from        acscon_user a with(nolock) 
    inner join  acscon_usercard b with(nolock)  on a.id = b.uid
    inner join  acscon_card c with(nolock)  on b.cardid = c.id
    inner join  acscon_cardtype f with(nolock)  on c.typeid = f.id
    inner join  acscon_groupmember d with(nolock)  on a.id = d.uid
    inner join  acscon_group e with(nolock)  on d.gid = e.id
    where usercode = '{person_code}' 
    and c.status = 1
    """)
    if results and len(results) > 0:
        person_cache[person_code] = results
        return True
    fail_reason = -2  # 人员凭证不存在
    return False


person_cache = {}

# usercode_cache = []

# def get_cache():
#     _get_cache()
#     _get_usercode_cache()


# def _get_cache():
#     person_cache.clear()
#     client = MSsqlClient(charset='cp936', **Config.module_config.huada.client_link)
#     results = client.select_to_dict("""
# select a.usercode as empo
# 	  ,a.name     as name_cn
# 	  ,a.sex      as sex
# 	  ,c.cardno   as card_id_dex
# 	  ,c.idtype   as idtype
# 	  ,c.startdate as validty_begintime
# 	  ,c.enddate  as validty_endtime
# 	  ,f.type     as card_type
# 	  ,e.name     as dept_name
# from        acscon_user a with(nolock) 
# inner join  acscon_usercard b with(nolock)  on a.id = b.uid
# inner join  acscon_card c with(nolock)  on b.cardid = c.id
# inner join  acscon_cardtype f with(nolock)  on c.typeid = f.id
# inner join  acscon_groupmember d with(nolock)  on a.id = d.uid
# inner join  acscon_group e with(nolock)  on d.gid = e.id
# where c.status = 1                         
#         """)
#     for result in results:
#         # 可能存在一人多凭证
#         if person_cache.get(result["empo"]):
#             person_cache[result["empo"]].append(result)
#         else:
#             person_cache[result["empo"]] = [result]
#     Mylogger.info(f"人员/凭证缓存初始化完成，共{len(person_cache)}人")


# def _get_usercode_cache():
#     usercode_cache.clear()
#     client = MSsqlClient(charset='cp936', **Config.module_config.huada.client_link)
#     results = client.select_to_dict("""
#     select usercode from acscon_user""")
#     for result in results:
#         usercode_cache.append(result["usercode"])
#     Mylogger.info(f"人员编码缓存初始化完成，共{len(usercode_cache)}人")
